use super::{expr::*, statements::*, syntaxResult::SyntaxResult};

pub struct VisitorPrinter {}
#[allow(non_snake_case)]
impl StmtVisit<String> for VisitorPrinter {
    fn visitExpressionStmt(&self, expr: &ExpressionStmt) -> Result<String, SyntaxResult> {
        self.print(&expr.expression)
    }

    fn visitPrinterStmt(&self, expr: &PrinterStmt) -> Result<String, SyntaxResult> {
        self.print(&expr.expression)
    }

    fn visitVariableStmt(&self, expr: &VariableDeclarationStmt) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitBlockStmt(&self, expr:&BlockStmt) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitIfStmt(&self, expr: &IfStmts) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitWhileStmt(&self, expr: &WhileStmts) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitFunctionStmt(&self, expr: &FunctionStmts) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitReturnStmt(&self, expr: &ReturnStmt) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitBreakStmt(&self, expr: &BreakStmt) -> Result<String, SyntaxResult> {
        todo!()
    }
}
#[allow(non_snake_case)]
impl VisitorPrinter {
    pub fn print(&self, expr: &SyntaxExpression) -> Result<String, SyntaxResult> {
        expr.accept::<String>(self)
    }
    fn parenTheSize(
        &self,
        name: &String,
        exprs: &[&SyntaxExpression],
    ) -> Result<String, SyntaxResult> {
        let mut builder = format!("({name}");

        for expr in exprs {
            builder = format!("{builder} {}", expr.accept::<String>(self)?);
        }

        builder = format!("{builder})");

        Ok(builder)
    }
    fn execute(&self, stmt: &Stmt) -> Result<String, SyntaxResult> {
        stmt.accept(self)
    }
    pub fn interpret(&self, stmts: &[Stmt]) -> bool {
        let mut hasError = false;
        for stmt in stmts {
            match self.execute(stmt) {
                Ok(str) => println!("{}", str),
                Err(e) => hasError = true,
            }
        }
        hasError
    }
}

#[allow(non_snake_case)]
impl ExpressionVisitor<String> for VisitorPrinter {
    fn visitBinaryExpression(&self, expr: &BinaryExpression) -> Result<String, SyntaxResult> {
        self.parenTheSize(expr.operator.as_string(), &[&expr.left, &expr.right])
    }

    fn visitGroupingExpression(&self, expr: &GroupingExpression) -> Result<String, SyntaxResult> {
        self.parenTheSize(&"Grouping".to_string(), &[&expr.expression])
    }

    fn visitLiteralExpression(&self, expr: &LiteralExpression) -> Result<String, SyntaxResult> {
        if let Some(value) = &expr.value {
            return Ok(value.to_string());
        }
        Ok("Nil".to_string())
    }

    fn visitUnaryExpression(&self, expr: &UnaryExpression) -> Result<String, SyntaxResult> {
        self.parenTheSize(expr.operator.as_string(), &[&expr.right])
    }

    fn visitProgramExpression(&self, expr: &ProgramExpression) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitVariableExpression(&self, expr: &VariableExpression) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitAssignmentExpression(
        &self,
        expr: &AssignmentExpression,
    ) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitLogicalExpression(&self, expr: &LogicalExpression) -> Result<String, SyntaxResult> {
        todo!()
    }

    fn visitCallExpression(&self, expr: &CallExpression) -> Result<String, SyntaxResult> {
        todo!()
    }
}
